#ifndef NOTIFIABLE_PROPERTIES_H_
#define NOTIFIABLE_PROPERTIES_H_

#include <QObject>
#include <vector>

#define JET_SINT    unsigned int
#define JET_BOOL    bool
#define JET_TRUE    true
#define JET_FALSE   false

///
/// \brief A notifiable boolean property.
///
class _declspec(dllexport) BoolProperty : public QObject
{
    Q_OBJECT

public:
    BoolProperty(bool defaultValue = true, QObject* parent = nullptr);
    BoolProperty(const BoolProperty& prop, QObject* parent = nullptr);

    bool Value() const;

    bool InternalValue() const;

    void operator =(bool value);
    void operator =(const BoolProperty& prop);

    bool operator == (bool value) const;
    bool operator == (const BoolProperty& prop) const;
    bool operator != (bool value) const;
    bool operator != (const BoolProperty& prop) const;

    operator bool() const;

    ///
    /// \brief Adds a property that this property is depended on.
    /// \param prop The dependent property
    /// \param value The property value that must be met in order for this property to be true.
    /// \return JET_TRUE if dependency is added, otherwise, there may have cyclic dependencies.
    ///
    JET_BOOL AddDependency(BoolProperty* prop, bool value = true);

    ///
    /// \brief Removes a dependent property.
    /// \param prop The property to be removed.
    /// \return JET_TRUE if successful.
    ///
    JET_BOOL RemoveDependency(BoolProperty* prop);

signals:
    void ValueChanged(bool newValue);
    void TrueSet();
    void FalseSet();

public slots:
    void SetValue(bool value);
    void SetSecurityValue(bool value);
    void SetToTrue();
    void SetToFalse();
    void SetValue(JET_SINT value);

private slots:
    void OnLinkedPropertyValueChanged(bool newValue);

private:
    ///
    /// \brief Evaluate property value with dependencies.
    /// \return The property value is true only when all dependent propertie's values
    /// equal to the preset values.
    ///
    void EvaluateValue();

    ///
    /// \brief Checkes whether if there has cyclic dependencies.
    /// \return JET_TRUE if base is also a dependency in the checking property's
    /// dependency path.
    ///
    JET_BOOL CyclicCheck(BoolProperty* base, BoolProperty* dependentProp);

private:
    bool _value;
    bool _internalValue;
    bool _securityValue;
#pragma warning(push)
#pragma warning(disable:4251)
    std::vector<std::pair<BoolProperty*, bool>> _linkedProperties;
#pragma warning(pop)
};

#endif